package com.icygen.eclipsetools.project;

import java.io.*;
import java.net.URI;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;

import com.icygen.core.CLibrary;
import com.icygen.core.db.ScriptRunner;
import com.icygen.eclipsetools.natures.IcygenProjectNature;
import com.icygen.eclipsetools.templates.TemplatesFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import com.icygen.eclipsetools.project.config.ApplicationConfig;
import com.icygen.eclipsetools.project.config.resources.db.Params;




public class IcygenProjectSupport {
	
	
	/**
     * For this marvelous project we need to:
     * - create the default Eclipse project
     * - add the custom project nature
     * - create the folder structure
     *
     * @param projectName
     * @param location
     * @param natureId
     * @return
     */
    public static IProject createProject(String projectName, URI location) {
        Assert.isNotNull(projectName);
        Assert.isTrue(projectName.trim().length() > 0);
 
        IProject project = createBaseProject(projectName, location);
        try {
            addNature(project);
            
            createProjectDirectories(project);
            
            createProjectConfigFiles(project);
            
            createApplicationBootstrap(project);
            
            createProjectIndexScript(project);
            
        } catch (CoreException e) {
            e.printStackTrace();
            project = null;
        }
 
        return project;
    }
 
    private static void createProjectDirectories(IProject project)
    											throws CoreException 
	{
    	String[] paths = 
        	{ 
				"htdocs/application/configs", 
				"htdocs/application/cache", 
				"htdocs/application/log", 
				"htdocs/application/modules",
				"htdocs/library", 
				"htdocs/cronjobs", 
				"htdocs/public/files", 
				"htdocs/public/scripts", 
				"htdocs/public/themes", 
        	};
        
        addToProjectStructure(project, paths);
        
        /*
         * Set Directory Permissions
         */
        IFolder projectCache = project.getFolder("htdocs/application/cache");
        CLibrary.chmod(projectCache.getFullPath().toString(), 0777);
        
        IFolder projectLog = project.getFolder("htdocs/application/log");
        CLibrary.chmod(projectLog.getFullPath().toString(), 0777);
        
        IFolder projectUserFiles = project.getFolder("htdocs/public/files");
        CLibrary.chmod(projectUserFiles.getFullPath().toString(), 0777);
	}
    
    
    private static void createProjectIndexScript(IProject project)
    												throws CoreException
    {
    	InputStream contentStream = TemplatesFactory.GetTemplate("index.php").openContentStream();
    	
    	IProgressMonitor monitor = null;
    	addFileToProject(project, new Path("htdocs/public/index.php"), contentStream, monitor);
    }
    
    private static void createApplicationBootstrap(IProject project)
													throws CoreException
	{
    	InputStream contentStream = TemplatesFactory.GetTemplate("ApplicationBootstrap.php").openContentStream();

    	IProgressMonitor monitor = null;
    	addFileToProject(project, new Path("htdocs/application/Bootstrap.php"), contentStream, monitor);
	}
    
    private static void createProjectConfigFiles(IProject project)
    												throws CoreException
    {
    	InputStream contentStream;
    	IProgressMonitor monitor;
    	
    	// Application Main Config
    	contentStream = TemplatesFactory.GetTemplate("application.xml").openContentStream();
    	monitor = null;
    	addFileToProject(project, new Path("htdocs/application/configs/application.xml"), contentStream, monitor);
    	
    	// Application Installed Modules
    	contentStream = TemplatesFactory.GetTemplate("installed.xml").openContentStream();
    	monitor = null;
    	addFileToProject(project, new Path("htdocs/application/configs/installed.xml"), contentStream, monitor);
    	
    	// Application Routes
    	contentStream = TemplatesFactory.GetTemplate("routes.xml").openContentStream();
    	monitor = null;
    	addFileToProject(project, new Path("htdocs/application/configs/routes.xml"), contentStream, monitor);
    	
    	// Application Settings Variables
    	contentStream = TemplatesFactory.GetTemplate("settings.xml").openContentStream();
    	monitor = null;
    	addFileToProject(project, new Path("htdocs/application/configs/settings.xml"), contentStream, monitor);
    }
    
    /**
     * Just do the basics: create a basic project.
     *
     * @param location
     * @param projectName
     */
    private static IProject createBaseProject(String projectName, URI location) {
        // it is acceptable to use the ResourcesPlugin class
        IProject newProject = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
 
        if (!newProject.exists()) {
            URI projectLocation = location;
            IProjectDescription desc = newProject.getWorkspace().newProjectDescription(newProject.getName());
            if (location != null && ResourcesPlugin.getWorkspace().getRoot().getLocationURI().equals(location)) {
                projectLocation = null;
            }
 
            desc.setLocationURI(projectLocation);
            try {
                newProject.create(desc, null);
                if (!newProject.isOpen()) {
                    newProject.open(null);
                }
            } catch (CoreException e) {
                e.printStackTrace();
            }
        }
 
        return newProject;
    }
 
    private static void createFolder(IFolder folder) 
    								throws CoreException 
    {
        IContainer parent = folder.getParent();
        if (parent instanceof IFolder) {
            createFolder((IFolder) parent);
        }
        if (!folder.exists()) {
            folder.create(false, true, null);
        }
    }
    
    
    /**
     * Adds a new file to the project.
     * 
     * @param container
     * @param path
     * @param contentStream
     * @param monitor
     * @throws CoreException
     */
    private static void addFileToProject(IProject project, 
								Path path,
								InputStream contentStream, 
								IProgressMonitor monitor)
										throws CoreException 
	{
        final IFile file = project.getFile(path);

        if (file.exists()) {
            file.setContents(contentStream, true, true, monitor);
        } else {
            file.create(contentStream, true, monitor);
        }

    }
 
    /**
     * Create a folder structure with a parent root, overlay, and a few child
     * folders.
     *
     * @param newProject
     * @param paths
     * @throws CoreException
     */
    private static void addToProjectStructure(IProject newProject, String[] paths)
    											throws CoreException 
    {
        for (String path : paths) {
            IFolder folder = newProject.getFolder(path);
            createFolder(folder);
        }
    }
 
    private static void addNature(IProject project) 
    								throws CoreException 
    {
        if (!project.hasNature(IcygenProjectNature.ID)) {
            IProjectDescription description = project.getDescription();
            String[] prevNatures = description.getNatureIds();
            String[] newNatures = new String[prevNatures.length + 1];
            System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length);
            newNatures[prevNatures.length] = IcygenProjectNature.ID;
            description.setNatureIds(newNatures);
 
            IProgressMonitor monitor = null;
            project.setDescription(description, monitor);
        }
    }
    
    public static ApplicationConfig getApplicationConfig(IProject project) 
    {
    	if(project == null) {
    		//throw new Exception("Project Cannot be NULL");
    	}
    	
    	//IPath path = project.getFullPath();
     	IPath location = project.getLocation();
     	// specify the location and name of xml file to be read
        File XMLfile = new File(location + "/htdocs/application/configs/application.xml");

        try {
        	// create JAXB context and initializing Marshaller
            JAXBContext jaxbContext = JAXBContext.newInstance(ApplicationConfig.class);
            Unmarshaller  jaxbUnmarshaller = jaxbContext.createUnmarshaller();
           	
            // this will create Java object - country from the XML file
            ApplicationConfig config = (ApplicationConfig) jaxbUnmarshaller.unmarshal(XMLfile);
            return config;
            
            


          
        
        } catch (JAXBException e) {
        	// some exception occured
        	e.printStackTrace();
     	}
        
        
        return new ApplicationConfig();
    }
    
    public static void setApplicationConfig(IProject project, ApplicationConfig config) 
    {
    	//IPath path = project.getFullPath();
     	IPath location = project.getLocation();
     	// specify the location and name of xml file to be read
        File XMLfile = new File(location + "/htdocs/application/configs/application.xml");
        
        try {
	        // create JAXB context and initializing Marshaller
	        JAXBContext jaxbContext = JAXBContext.newInstance(ApplicationConfig.class);
	        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
	        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
	        //specify the location and name of xml file to be created
	        
	        jaxbMarshaller.marshal(config, XMLfile);
	        jaxbMarshaller.marshal(config, System.out);
        } catch (JAXBException e) {
        	// some exception occured
        	e.printStackTrace();
     	}
         
    }
    
    public static void createProjectDatabase(IProject project)
    {
    	try {
			ApplicationConfig config = getApplicationConfig(project);
			Params configDbParams = config.getDevelopmentConfig().getResources().getDb().getParams();
			
			String host = configDbParams.getHost();
			String dbname = configDbParams.getDbname();
			String user = configDbParams.getUsername();
			String pass = configDbParams.getPassword();
			
			/*
			 * Create Mysql Connection
			 */
			String dsn = String.format("jdbc:mysql://%s/%s?user=%s&password=%s", host, dbname, user, pass);
			Class.forName("com.mysql.jdbc.Driver");
			Connection con = DriverManager.getConnection(dsn);
			
			/*
			 * Execute Sql File
			 */
			InputStreamReader isr = new InputStreamReader(IcygenProjectSupport.class.getClassLoader().getResourceAsStream("/resources/IcygenProject.sql"));
			ScriptRunner runner = new ScriptRunner(con, true, false);
			runner.runScript(new BufferedReader(isr));
		}
		catch(Exception e) {
			System.out.println(e.getMessage());
		} 
    }
}


 

